/**
 * Downward compatible, touchable dial
 *
 * Version: 1.2.11
 * Requires: jQuery v1.7+
 *
 * Copyright (c) 2012 Anthony Terrien
 * Under MIT License (http://www.opensource.org/licenses/mit-license.php)
 *
 * Thanks to vor, eskimoblood, spiffistan, FabrizioC
 */
(function(e) {
    if (typeof exports === "object") {
        module.exports = e(require("jquery"))
    } else if (typeof define === "function" && define.amd) {
        define(["jquery"], e)
    } else {
        e(jQuery)
    }
})(function(e) {
    "use strict";
    var t = {},
    n = Math.max,
    r = Math.min;
    t.c = {};
    t.c.d = e(document);
    t.c.t = function(e) {
        return e.originalEvent.touches.length - 1
    };
    t.o = function() {
        var n = this;
        this.o = null;
        this.$ = null;
        this.i = null;
        this.g = null;
        this.v = null;
        this.cv = null;
        this.x = 0;
        this.y = 0;
        this.w = 0;
        this.h = 0;
        this.$c = null;
        this.c = null;
        this.t = 0;
        this.isInit = false;
        this.fgColor = null;
        this.pColor = null;
        this.dH = null;
        this.cH = null;
        this.eH = null;
        this.rH = null;
        this.scale = 1;
        this.relative = false;
        this.relativeWidth = false;
        this.relativeHeight = false;
        this.$div = null;
        this.run = function() {
            var t = function(e, t) {
                var r;
                for (r in t) {
                    n.o[r] = t[r]
                }
                n._carve().init();
                n._configure()._draw()
            };
            if (this.$.data("kontroled")) return;
            this.$.data("kontroled", true);
            this.extend();
            this.o = e.extend({
                min: this.$.data("min") !== undefined ? this.$.data("min") : 0,
                max: this.$.data("max") !== undefined ? this.$.data("max") : 100,
                stopper: true,
                readOnly: this.$.data("readonly") || this.$.attr("readonly") === "readonly",
                cursor: this.$.data("cursor") === true && 30 || this.$.data("cursor") || 0,
                thickness: this.$.data("thickness") && Math.max(Math.min(this.$.data("thickness"), 1), .01) || .35,
                lineCap: this.$.data("linecap") || "butt",
                width: this.$.data("width") || 200,
                height: this.$.data("height") || 200,
                displayInput: this.$.data("displayinput") == null || this.$.data("displayinput"),
                displayPrevious: this.$.data("displayprevious"),
                fgColor: this.$.data("fgcolor") || "#87CEEB",
                inputColor: this.$.data("inputcolor"),
                font: this.$.data("font") || "Arial",
                fontWeight: this.$.data("font-weight") || "bold",
                inline: false,
                step: this.$.data("step") || 1,
                rotation: this.$.data("rotation"),
                draw: null,
                change: null,
                cancel: null,
                release: null,
                format: function(e) {
                    return e
                },
                parse: function(e) {
                    return parseFloat(e)
                }
            },
            this.o);
            this.o.flip = this.o.rotation === "anticlockwise" || this.o.rotation === "acw";
            if (!this.o.inputColor) {
                this.o.inputColor = this.o.fgColor
            }
            if (this.$.is("fieldset")) {
                this.v = {};
                this.i = this.$.find("input");
                this.i.each(function(t) {
                    var r = e(this);
                    n.i[t] = r;
                    n.v[t] = n.o.parse(r.val());
                    r.bind("change blur",
                    function() {
                        var e = {};
                        e[t] = r.val();
                        n.val(n._validate(e))
                    })
                });
                this.$.find("legend").remove()
            } else {
                this.i = this.$;
                this.v = this.o.parse(this.$.val());
                this.v === "" && (this.v = this.o.min);
                this.$.bind("change blur",
                function() {
                    n.val(n._validate(n.o.parse(n.$.val())))
                })
            } ! this.o.displayInput && this.$.hide();
            this.$c = e(document.createElement("canvas")).attr({
                width: this.o.width,
                height: this.o.height
            });
            this.$div = e('<div style="' + (this.o.inline ? "display:inline;": "") + "width:" + this.o.width + "px;height:" + this.o.height + "px;" + '"></div>');
            this.$.wrap(this.$div).before(this.$c);
            this.$div = this.$.parent();
            if (typeof G_vmlCanvasManager !== "undefined") {
                G_vmlCanvasManager.initElement(this.$c[0])
            }
            this.c = this.$c[0].getContext ? this.$c[0].getContext("2d") : null;
            if (!this.c) {
                throw {
                    name: "CanvasNotSupportedException",
                    message: "Canvas not supported. Please use excanvas on IE8.0.",
                    toString: function() {
                        return this.name + ": " + this.message
                    }
                }
            }
            this.scale = (window.devicePixelRatio || 1) / (this.c.webkitBackingStorePixelRatio || this.c.mozBackingStorePixelRatio || this.c.msBackingStorePixelRatio || this.c.oBackingStorePixelRatio || this.c.backingStorePixelRatio || 1);
            this.relativeWidth = this.o.width % 1 !== 0 && this.o.width.indexOf("%");
            this.relativeHeight = this.o.height % 1 !== 0 && this.o.height.indexOf("%");
            this.relative = this.relativeWidth || this.relativeHeight;
            this._carve();
            if (this.v instanceof Object) {
                this.cv = {};
                this.copy(this.v, this.cv)
            } else {
                this.cv = this.v
            }
            this.$.bind("configure", t).parent().bind("configure", t);
            this._listen()._configure()._xy().init();
            this.isInit = true;
            this.$.val(this.o.format(this.v));
            this._draw();
            return this
        };
        this._carve = function() {
            if (this.relative) {
                var e = this.relativeWidth ? this.$div.parent().width() * parseInt(this.o.width) / 100 : this.$div.parent().width(),
                t = this.relativeHeight ? this.$div.parent().height() * parseInt(this.o.height) / 100 : this.$div.parent().height();
                this.w = this.h = Math.min(e, t)
            } else {
                this.w = this.o.width;
                this.h = this.o.height
            }
            this.$div.css({
                width: this.w + "px",
                height: this.h + "px"
            });
            this.$c.attr({
                width: this.w,
                height: this.h
            });
            if (this.scale !== 1) {
                this.$c[0].width = this.$c[0].width * this.scale;
                this.$c[0].height = this.$c[0].height * this.scale;
                this.$c.width(this.w);
                this.$c.height(this.h)
            }
            return this
        };
        this._draw = function() {
            var e = true;
            n.g = n.c;
            n.clear();
            n.dH && (e = n.dH());
            e !== false && n.draw()
        };
        this._touch = function(e) {
            var r = function(e) {
                var t = n.xy2val(e.originalEvent.touches[n.t].pageX, e.originalEvent.touches[n.t].pageY);
                if (t == n.cv) return;
                if (n.cH && n.cH(t) === false) return;
                n.change(n._validate(t));
                n._draw()
            };
            this.t = t.c.t(e);
            r(e);
            t.c.d.bind("touchmove.k", r).bind("touchend.k",
            function() {
                t.c.d.unbind("touchmove.k touchend.k");
                n.val(n.cv)
            });
            return this
        };
        this._mouse = function(e) {
            var r = function(e) {
                var t = n.xy2val(e.pageX, e.pageY);
                if (t == n.cv) return;
                if (n.cH && n.cH(t) === false) return;
                n.change(n._validate(t));
                n._draw()
            };
            r(e);
            t.c.d.bind("mousemove.k", r).bind("keyup.k",
            function(e) {
                if (e.keyCode === 27) {
                    t.c.d.unbind("mouseup.k mousemove.k keyup.k");
                    if (n.eH && n.eH() === false) return;
                    n.cancel()
                }
            }).bind("mouseup.k",
            function(e) {
                t.c.d.unbind("mousemove.k mouseup.k keyup.k");
                n.val(n.cv)
            });
            return this
        };
        this._xy = function() {
            var e = this.$c.offset();
            this.x = e.left;
            this.y = e.top;
            return this
        };
        this._listen = function() {
            if (!this.o.readOnly) {
                this.$c.bind("mousedown",
                function(e) {
                    e.preventDefault();
                    n._xy()._mouse(e)
                }).bind("touchstart",
                function(e) {
                    e.preventDefault();
                    n._xy()._touch(e)
                });
                this.listen()
            } else {
                this.$.attr("readonly", "readonly")
            }
            if (this.relative) {
                e(window).resize(e.debounce(50,
                function() {
                    n._carve().init();
                    n._draw()
                }))
            }
            return this
        };
        this._configure = function() {
            if (this.o.draw) this.dH = this.o.draw;
            if (this.o.change) this.cH = this.o.change;
            if (this.o.cancel) this.eH = this.o.cancel;
            if (this.o.release) this.rH = this.o.release;
            if (this.o.displayPrevious) {
                this.pColor = this.h2rgba(this.o.fgColor, "0.4");
                this.fgColor = this.h2rgba(this.o.fgColor, "0.6")
            } else {
                this.fgColor = this.o.fgColor
            }
            return this
        };
        this._clear = function() {
            this.$c[0].width = this.$c[0].width
        };
        this._validate = function(e) {
            var t = ~~ ((e < 0 ? -.5 : .5) + e / this.o.step) * this.o.step;
            return Math.round(t * 100) / 100
        };
        this.listen = function() {};
        this.extend = function() {};
        this.init = function() {};
        this.change = function(e) {};
        this.val = function(e) {};
        this.xy2val = function(e, t) {};
        this.draw = function() {};
        this.clear = function() {
            this._clear()
        };
        this.h2rgba = function(e, t) {
            var n;
            e = e.substring(1, 7);
            n = [parseInt(e.substring(0, 2), 16), parseInt(e.substring(2, 4), 16), parseInt(e.substring(4, 6), 16)];
            return "rgba(" + n[0] + "," + n[1] + "," + n[2] + "," + t + ")"
        };
        this.copy = function(e, t) {
            for (var n in e) {
                t[n] = e[n]
            }
        }
    };
    t.Dial = function() {
        t.o.call(this);
        this.startAngle = null;
        this.xy = null;
        this.radius = null;
        this.lineWidth = null;
        this.cursorExt = null;
        this.w2 = null;
        this.PI2 = 2 * Math.PI;
        this.extend = function() {
            this.o = e.extend({
                bgColor: this.$.data("bgcolor") || "#EEEEEE",
                angleOffset: this.$.data("angleoffset") || 0,
                angleArc: this.$.data("anglearc") || 360,
                inline: true
            },
            this.o)
        };
        this.val = function(e, t) {
            if (null != e) {
                e = this.o.parse(e);
                if (t !== false && e != this.v && this.rH && this.rH(e) === false) {
                    return
                }
                this.cv = this.o.stopper ? n(r(e, this.o.max), this.o.min) : e;
                this.v = this.cv;
                this.$.val(this.o.format(this.v));
                this._draw()
            } else {
                return this.v
            }
        };
        this.xy2val = function(e, t) {
            var i, s;
            i = Math.atan2(e - (this.x + this.w2), -(t - this.y - this.w2)) - this.angleOffset;
            if (this.o.flip) {
                i = this.angleArc - i - this.PI2
            }
            if (this.angleArc != this.PI2 && i < 0 && i > -.5) {
                i = 0
            } else if (i < 0) {
                i += this.PI2
            }
            s = i * (this.o.max - this.o.min) / this.angleArc + this.o.min;
            this.o.stopper && (s = n(r(s, this.o.max), this.o.min));
            return s
        };
        this.listen = function() {
            var t = this,
            i, s, o = function(e) {
                e.preventDefault();
                var o = e.originalEvent,
                u = o.detail || o.wheelDeltaX,
                a = o.detail || o.wheelDeltaY,
                f = t._validate(t.o.parse(t.$.val())) + (u > 0 || a > 0 ? t.o.step: u < 0 || a < 0 ? -t.o.step: 0);
                f = n(r(f, t.o.max), t.o.min);
                t.val(f, false);
                if (t.rH) {
                    clearTimeout(i);
                    i = setTimeout(function() {
                        t.rH(f);
                        i = null
                    },
                    100);
                    if (!s) {
                        s = setTimeout(function() {
                            if (i) t.rH(f);
                            s = null
                        },
                        200)
                    }
                }
            },
            u,
            a,
            f = 1,
            l = {
                37 : -t.o.step,
                38 : t.o.step,
                39 : t.o.step,
                40 : -t.o.step
            };
            this.$.bind("keydown",
            function(i) {
                var s = i.keyCode;
                if (s >= 96 && s <= 105) {
                    s = i.keyCode = s - 48
                }
                u = parseInt(String.fromCharCode(s));
                if (isNaN(u)) {
                    s !== 13 && s !== 8 && s !== 9 && s !== 189 && (s !== 190 || t.$.val().match(/\./)) && i.preventDefault();
                    if (e.inArray(s, [37, 38, 39, 40]) > -1) {
                        i.preventDefault();
                        var o = t.o.parse(t.$.val()) + l[s] * f;
                        t.o.stopper && (o = n(r(o, t.o.max), t.o.min));
                        t.change(t._validate(o));
                        t._draw();
                        a = window.setTimeout(function() {
                            f *= 2
                        },
                        30)
                    }
                }
            }).bind("keyup",
            function(e) {
                if (isNaN(u)) {
                    if (a) {
                        window.clearTimeout(a);
                        a = null;
                        f = 1;
                        t.val(t.$.val())
                    }
                } else {
                    t.$.val() > t.o.max && t.$.val(t.o.max) || t.$.val() < t.o.min && t.$.val(t.o.min)
                }
            });
            this.$c.bind("mousewheel DOMMouseScroll", o);
            this.$.bind("mousewheel DOMMouseScroll", o)
        };
        this.init = function() {
            if (this.v < this.o.min || this.v > this.o.max) {
                this.v = this.o.min
            }
            this.$.val(this.v);
            this.w2 = this.w / 2;
            this.cursorExt = this.o.cursor / 100;
            this.xy = this.w2 * this.scale;
            this.lineWidth = this.xy * this.o.thickness;
            this.lineCap = this.o.lineCap;
            this.radius = this.xy - this.lineWidth / 2;
            this.o.angleOffset && (this.o.angleOffset = isNaN(this.o.angleOffset) ? 0 : this.o.angleOffset);
            this.o.angleArc && (this.o.angleArc = isNaN(this.o.angleArc) ? this.PI2: this.o.angleArc);
            this.angleOffset = this.o.angleOffset * Math.PI / 180;
            this.angleArc = this.o.angleArc * Math.PI / 180;
            this.startAngle = 1.5 * Math.PI + this.angleOffset;
            this.endAngle = 1.5 * Math.PI + this.angleOffset + this.angleArc;
            var e = n(String(Math.abs(this.o.max)).length, String(Math.abs(this.o.min)).length, 2) + 2;
            this.o.displayInput && this.i.css({
                width: (this.w / 2 + 4 >> 0) + "px",
                height: (this.w / 3 >> 0) + "px",
                position: "absolute",
                "vertical-align": "middle",
                "margin-top": (this.w / 3 >> 0) + "px",
                "margin-left": "-" + (this.w * 3 / 4 + 2 >> 0) + "px",
                border: 0,
                background: "none",
                font: this.o.fontWeight + " " + (this.w / e >> 0) + "px " + this.o.font,
                "text-align": "center",
                color: this.o.inputColor || this.o.fgColor,
                padding: "0px",
                "-webkit-appearance": "none"
            }) || this.i.css({
                width: "0px",
                visibility: "hidden"
            })
        };
        this.change = function(e) {
            this.cv = e;
            this.$.val(this.o.format(e))
        };
        this.angle = function(e) {
            return (e - this.o.min) * this.angleArc / (this.o.max - this.o.min)
        };
        this.arc = function(e) {
            var t, n;
            e = this.angle(e);
            if (this.o.flip) {
                t = this.endAngle + 1e-5;
                n = t - e - 1e-5
            } else {
                t = this.startAngle - 1e-5;
                n = t + e + 1e-5
            }
            this.o.cursor && (t = n - this.cursorExt) && (n = n + this.cursorExt);
            return {
                s: t,
                e: n,
                d: this.o.flip && !this.o.cursor
            }
        };
        this.draw = function() {
            var e = this.g,
            t = this.arc(this.cv),
            n,
            r = 1;
            e.lineWidth = this.lineWidth;
            e.lineCap = this.lineCap;
            if (this.o.bgColor !== "none") {
                e.beginPath();
                e.strokeStyle = this.o.bgColor;
                e.arc(this.xy, this.xy, this.radius, this.endAngle - 1e-5, this.startAngle + 1e-5, true);
                e.stroke()
            }
            if (this.o.displayPrevious) {
                n = this.arc(this.v);
                e.beginPath();
                e.strokeStyle = this.pColor;
                e.arc(this.xy, this.xy, this.radius, n.s, n.e, n.d);
                e.stroke();
                r = this.cv == this.v
            }
            e.beginPath();
            e.strokeStyle = r ? this.o.fgColor: this.fgColor;
            e.arc(this.xy, this.xy, this.radius, t.s, t.e, t.d);
            e.stroke()
        };
        this.cancel = function() {
            this.val(this.v)
        }
    };
    e.fn.dial = e.fn.knob = function(n) {
        return this.each(function() {
            var r = new t.Dial;
            r.o = n;
            r.$ = e(this);
            r.run()
        }).parent()
    }
})